"""
剪映导出控制器
基于pyJianYingDraft的导出功能，提供草稿导出服务
"""

import os
import time
import shutil
import logging
from typing import Optional, Dict, Any
from datetime import datetime
from enum import Enum

try:
    import uiautomation as uia
    UI_AUTOMATION_AVAILABLE = True
except ImportError:
    UI_AUTOMATION_AVAILABLE = False
    print("警告: uiautomation库未安装，导出功能将不可用")

# 导入父目录的模块
import sys
parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, parent_dir)

try:
    from pyJianYingDraft.jianying_controller import ExportResolution, ExportFramerate, ControlFinder
    from pyJianYingDraft import exceptions
    from pyJianYingDraft.exceptions import AutomationError
except ImportError as e:
    print(f"警告: 无法导入pyJianYingDraft模块: {e}")
    # 如果导入失败，定义基本的枚举类型
    class ExportResolution(Enum):
        RES_8K = "8K"
        RES_4K = "4K"
        RES_2K = "2K"
        RES_1080P = "1080P"
        RES_720P = "720P"
        RES_480P = "480P"

    class ExportFramerate(Enum):
        FR_24 = "24fps"
        FR_25 = "25fps"
        FR_30 = "30fps"
        FR_50 = "50fps"
        FR_60 = "60fps"

    class AutomationError(Exception):
        pass

    class ControlFinder:
        """控件查找器，封装部分与控件查找相关的逻辑"""

        @staticmethod
        def desc_matcher(target_desc: str, depth: int = 2, exact: bool = False):
            """根据full_description查找控件的匹配器"""
            target_desc = target_desc.lower()
            def matcher(control, _depth: int) -> bool:
                if _depth != depth:
                    return False
                try:
                    full_desc: str = control.GetPropertyValue(30159).lower()
                    return (target_desc == full_desc) if exact else (target_desc in full_desc)
                except:
                    return False
            return matcher

        @staticmethod
        def class_name_matcher(class_name: str, depth: int = 1, exact: bool = False):
            """根据ClassName查找控件的匹配器"""
            class_name = class_name.lower()
            def matcher(control, _depth: int) -> bool:
                if _depth != depth:
                    return False
                try:
                    curr_class_name: str = control.ClassName.lower()
                    return (class_name == curr_class_name) if exact else (class_name in curr_class_name)
                except:
                    return False
            return matcher


class ExportController:
    """剪映导出控制器"""

    def __init__(self):
        self.app = None
        self.app_status = None

        # 配置日志
        self.logger = logging.getLogger(__name__)
        if not self.logger.handlers:
            handler = logging.StreamHandler()
            formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
            handler.setFormatter(formatter)
            self.logger.addHandler(handler)
            self.logger.setLevel(logging.INFO)

        if not UI_AUTOMATION_AVAILABLE:
            self.logger.error("UIAutomation库不可用，导出功能将无法正常工作")

    def check_window_exists(self) -> bool:
        """检查剪映窗口是否存在（轻量级检查，不激活窗口）"""
        if not UI_AUTOMATION_AVAILABLE:
            return False

        try:
            # 只检查窗口是否存在，不激活
            app = uia.WindowControl(searchDepth=1, Compare=self._jianying_window_cmp)
            return app.Exists(0)
        except Exception as e:
            self.logger.debug(f"检查剪映窗口存在性失败: {e}")
            return False

    def get_window(self) -> bool:
        """寻找剪映窗口并置顶"""
        if not UI_AUTOMATION_AVAILABLE:
            raise AutomationError("UIAutomation库不可用")

        try:
            if hasattr(self, "app") and self.app and self.app.Exists(0):
                self.app.SetTopmost(False)

            self.app = uia.WindowControl(searchDepth=1, Compare=self._jianying_window_cmp)
            if not self.app.Exists(0):
                return False

            # 寻找可能存在的导出窗口
            export_window = self.app.WindowControl(searchDepth=1, Name="导出")
            if export_window.Exists(0):
                self.app = export_window
                self.app_status = "pre_export"

            self.app.SetActive()
            self.app.SetTopmost()
            return True
        except Exception as e:
            self.logger.error(f"获取剪映窗口失败: {e}")
            return False

    def _jianying_window_cmp(self, control, depth: int) -> bool:
        """剪映窗口比较器"""
        if control.Name != "剪映专业版":
            return False
        if "HomePage".lower() in control.ClassName.lower():
            self.app_status = "home"
            return True
        if "MainWindow".lower() in control.ClassName.lower():
            self.app_status = "edit"
            return True
        return False

    def switch_to_home(self) -> bool:
        """切换到剪映主页"""
        if self.app_status == "home":
            return True
        if self.app_status != "edit":
            self.logger.error("仅支持从编辑模式切换到主页")
            return False

        try:
            close_btn = self.app.GroupControl(searchDepth=1, ClassName="TitleBarButton", foundIndex=3)
            close_btn.Click(simulateMove=False)
            time.sleep(2)
            return self.get_window()
        except Exception as e:
            self.logger.error(f"切换到主页失败: {e}")
            return False

    def find_draft(self, draft_name: str) -> bool:
        """查找指定名称的草稿"""
        try:
            # 确保在主页
            if not self.get_window():
                return False

            if not self.switch_to_home():
                return False

            # 查找草稿
            draft_name_text = self.app.TextControl(
                searchDepth=2,
                Compare=self._desc_matcher(f"HomePageDraftTitle:{draft_name}", exact=True)
            )

            return draft_name_text.Exists(0)
        except Exception as e:
            self.logger.error(f"查找草稿失败: {e}")
            return False

    def _desc_matcher(self, target_desc: str, depth: int = 2, exact: bool = False):
        """根据description查找控件的匹配器"""
        target_desc = target_desc.lower()
        def matcher(control, _depth: int) -> bool:
            if _depth != depth:
                return False
            try:
                full_desc: str = control.GetPropertyValue(30159).lower()
                return (target_desc == full_desc) if exact else (target_desc in full_desc)
            except:
                return False
        return matcher

    def export_draft(self, draft_name: str, output_path: Optional[str] = None, *,
                     resolution: Optional[ExportResolution] = None,
                     framerate: Optional[ExportFramerate] = None,
                     timeout: float = 1200, task_id: Optional[str] = None) -> Dict[str, Any]:
        """导出指定的剪映草稿

        Args:
            draft_name: 要导出的剪映草稿名称
            output_path: 导出路径, 支持指向文件夹或直接指向文件
            resolution: 导出分辨率
            framerate: 导出帧率
            timeout: 导出超时时间(秒)

        Returns:
            包含导出结果的字典
        """
        result = {
            "success": False,
            "message": "",
            "timestamp": datetime.now().isoformat(),
            "draft_name": draft_name,
            "output_path": output_path
        }

        if not UI_AUTOMATION_AVAILABLE:
            result["message"] = "UIAutomation库不可用"
            return result

        try:
            self.logger.info(f"开始导出草稿: {draft_name} 至 {output_path}")

            # 1. 获取剪映窗口
            if not self.get_window():
                result["message"] = "未找到剪映窗口"
                self.logger.error(result["message"])
                return result

            # 2. 切换到主页
            if not self.switch_to_home():
                result["message"] = "切换到主页失败"
                return result

            # 3. 点击对应草稿
            draft_name_text = self.app.TextControl(
                searchDepth=2,
                Compare=self._desc_matcher(f"HomePageDraftTitle:{draft_name}", exact=True)
            )
            if not draft_name_text.Exists(0):
                result["message"] = f"未找到名为{draft_name}的剪映草稿"
                return result

            draft_btn = draft_name_text.GetParentControl()
            if not draft_btn:
                result["message"] = "无法获取草稿按钮"
                return result

            draft_btn.Click(simulateMove=False)
            time.sleep(10)

            if not self.get_window():
                result["message"] = "打开草稿后无法获取窗口"
                return result

            # 4. 点击导出按钮
            export_btn = self.app.TextControl(
                searchDepth=2,
                Compare=self._desc_matcher("MainWindowTitleBarExportBtn")
            )
            if not export_btn.Exists(0):
                result["message"] = "未在编辑窗口中找到导出按钮"
                return result

            export_btn.Click(simulateMove=False)
            time.sleep(10)

            if not self.get_window():
                result["message"] = "点击导出按钮后无法获取窗口"
                return result

            # 5. 获取原始导出路径
            export_path_sib = self.app.TextControl(
                searchDepth=2,
                Compare=self._desc_matcher("ExportPath")
            )
            if not export_path_sib.Exists(0):
                result["message"] = "未找到导出路径框"
                return result

            export_path_text = export_path_sib.GetSiblingControl(lambda ctrl: True)
            if not export_path_text:
                result["message"] = "无法获取导出路径文本"
                return result

            export_path = export_path_text.GetPropertyValue(30159)
            self.logger.info(f"原始导出路径: {export_path}")

            # 6. 设置分辨率
            if resolution is not None:
                if not self._set_export_resolution(resolution):
                    result["message"] = f"设置分辨率{resolution.value}失败"
                    return result

            # 7. 设置帧率
            if framerate is not None:
                if not self._set_export_framerate(framerate):
                    result["message"] = f"设置帧率{framerate.value}失败"
                    return result

            # 8. 开始导出
            export_btn = self.app.TextControl(
                searchDepth=2,
                Compare=self._desc_matcher("ExportOkBtn", exact=True)
            )
            if not export_btn.Exists(0):
                result["message"] = "未在导出窗口中找到导出按钮"
                return result

            export_btn.Click(simulateMove=False)
            time.sleep(5)

            # 9. 等待导出完成
            self.logger.info("等待导出完成...")
            start_time = time.time()

            while True:
                if not self.get_window():
                    continue

                if self.app_status != "pre_export":
                    continue

                succeed_close_btn = self.app.TextControl(
                    searchDepth=2,
                    Compare=self._desc_matcher("ExportSucceedCloseBtn")
                )
                if succeed_close_btn.Exists(0):
                    succeed_close_btn.Click(simulateMove=False)
                    break

                if time.time() - start_time > timeout:
                    result["message"] = f"导出超时, 时限为{timeout}秒"
                    return result

                time.sleep(1)

            time.sleep(2)

            # 10. 回到目录页
            if not self.get_window():
                self.logger.warning("导出完成后无法获取窗口")
            else:
                self.switch_to_home()

            # 11. 取消置顶状态，避免剪映窗口一直在最前面
            try:
                if self.app and self.app.Exists(0):
                    self.app.SetTopmost(False)
                    self.logger.info("已取消剪映窗口置顶状态")
            except Exception as e:
                self.logger.warning(f"取消置顶状态失败: {e}")

            time.sleep(2)

            # 12. 移动文件到指定目录
            if output_path is not None:
                try:
                    # 确保目标目录存在
                    if os.path.isdir(output_path):
                        # 如果是目录，使用原文件名
                        filename = os.path.basename(export_path)
                        final_path = os.path.join(output_path, filename)
                    else:
                        # 如果是文件路径，确保目录存在
                        os.makedirs(os.path.dirname(output_path), exist_ok=True)
                        final_path = output_path

                    shutil.move(export_path, final_path)
                    result["final_path"] = final_path
                    self.logger.info(f"文件已移动到: {final_path}")
                except Exception as e:
                    self.logger.warning(f"移动文件失败: {e}，文件仍在原位置: {export_path}")
                    result["final_path"] = export_path
            else:
                result["final_path"] = export_path

            result["success"] = True
            result["message"] = "导出成功"
            self.logger.info(f"草稿 {draft_name} 导出完成")
            return result

        except Exception as e:
            result["message"] = f"导出异常: {str(e)}"
            self.logger.error(f"导出异常: {str(e)}")
            import traceback
            self.logger.error(f"异常详情: {traceback.format_exc()}")
            return result

    def _set_export_resolution(self, resolution: ExportResolution) -> bool:
        """设置导出分辨率"""
        try:
            setting_group = self.app.GroupControl(
                searchDepth=1,
                Compare=lambda ctrl, depth: "PanelSettingsGroup_QMLTYPE" in ctrl.ClassName.lower() if depth == 1 else False
            )
            if not setting_group.Exists(0):
                self.logger.error("未找到导出设置组")
                return False

            resolution_btn = setting_group.TextControl(
                searchDepth=2,
                Compare=self._desc_matcher("ExportSharpnessInput")
            )
            if not resolution_btn.Exists(0.5):
                self.logger.error("未找到导出分辨率下拉框")
                return False

            resolution_btn.Click(simulateMove=False)
            time.sleep(0.5)

            resolution_item = self.app.TextControl(
                searchDepth=2,
                Compare=self._desc_matcher(resolution.value)
            )
            if not resolution_item.Exists(0.5):
                self.logger.error(f"未找到{resolution.value}分辨率选项")
                return False

            resolution_item.Click(simulateMove=False)
            time.sleep(0.5)
            return True
        except Exception as e:
            self.logger.error(f"设置分辨率失败: {e}")
            return False

    def _set_export_framerate(self, framerate: ExportFramerate) -> bool:
        """设置导出帧率"""
        try:
            setting_group = self.app.GroupControl(
                searchDepth=1,
                Compare=lambda ctrl, depth: "PanelSettingsGroup_QMLTYPE" in ctrl.ClassName.lower() if depth == 1 else False
            )
            if not setting_group.Exists(0):
                self.logger.error("未找到导出设置组")
                return False

            framerate_btn = setting_group.TextControl(
                searchDepth=2,
                Compare=self._desc_matcher("FrameRateInput")
            )
            if not framerate_btn.Exists(0.5):
                self.logger.error("未找到导出帧率下拉框")
                return False

            framerate_btn.Click(simulateMove=False)
            time.sleep(0.5)

            framerate_item = self.app.TextControl(
                searchDepth=2,
                Compare=self._desc_matcher(framerate.value)
            )
            if not framerate_item.Exists(0.5):
                self.logger.error(f"未找到{framerate.value}帧率选项")
                return False

            framerate_item.Click(simulateMove=False)
            time.sleep(0.5)
            return True
        except Exception as e:
            self.logger.error(f"设置帧率失败: {e}")
            return False

    def list_drafts(self) -> Dict[str, Any]:
        """获取草稿列表"""
        result = {
            "success": False,
            "drafts": [],
            "message": "",
            "timestamp": datetime.now().isoformat()
        }

        if not UI_AUTOMATION_AVAILABLE:
            result["message"] = "UIAutomation库不可用"
            return result

        try:
            if not self.get_window():
                result["message"] = "未找到剪映窗口"
                return result

            if not self.switch_to_home():
                result["message"] = "切换到主页失败"
                return result

            # 这里可以添加获取草稿列表的逻辑
            # 由于剪映界面的复杂性，这个功能可能需要更详细的实现

            result["success"] = True
            result["message"] = "草稿列表获取功能待实现"
            return result

        except Exception as e:
            result["message"] = f"获取草稿列表异常: {str(e)}"
            self.logger.error(f"获取草稿列表异常: {str(e)}")
            return result